import {DatePartDescriber} from "./describers/date";
import {HourPartDescriber} from "./describers/hour";
import {MinutePartDescriber} from "./describers/minute";
import {MonthPartDescriber} from "./describers/month";
import {WeekPartDescriber} from "./describers/week";
import {PreNormalized} from "./types";

function numberthize(num: string) {
  const n = parseInt(num);

  switch (20 < n ? n % 10 : n) {
    case 1:
      return num + "st";

    case 2:
      return num + "nd";

    case 3:
      return num + "rd";

    default:
      return num + "th";
  }
}

function segmentDesc(exp, meaning, n, r) {
  if ("*" === exp) {
    return "every " + meaning;
  } else {
    return function (e, t, n, r) {
      let o = e.match(/\d+|./g).map(function (e) {
        const t = Number(e);
        return isNaN(t) ? e : t;
      });
      const a = o[0];


      if (Number.isInteger(a)) {
        if (1 === o.length) return "" + (n[a] || a); // 2 =？ 二月

        if (3 === o.length && "/" === o[1] && Number.isInteger(o[2])) return "每隔" + numberthize(o[2]) + " " + t + " from " + (n[a] || a) + " through " + (n[r] || r);
        if (3 === o.length && "-" === o[1] && Number.isInteger(o[2]) && o[2] >= a) return "every " + t + " from " + (n[a] || a) + " through " + (n[o[2]] || o[2]);
        if (5 === o.length && "-" === o[1] && Number.isInteger(o[2]) && o[2] >= a && "/" === o[3] && Number.isInteger(o[4]) && 1 <= o[4]) return "every " + numberthize(o[4]) + " " + t + " from " + (n[a] || a) + " through " + (n[o[2]] || o[2]);
      } else if (3 === o.length && "/" === o[1] && Number.isInteger(o[2]) && "*" === o[0]) return "每" + `${o[2]}个` + t;

      return "";
    }(exp, meaning, n, r);
  }
}

type Meaning = "月" | "号" | "hour" | "minute" | "day-of-week"

function expandPartToDesc(seg: string, meaning: Meaning, n: {}, maxValue: number, o = null) {
  const group = seg.split(",");


  const smallSeg = group.map(function (exp) {
    return segmentDesc(exp, meaning, n, maxValue);
  })

  return ((o ? "" : meaning + " ") + function (e) {
    switch (e.length) {
      case 0:
        return "";

      case 1:
        return e[0];

      case 2:
        return e[0] + "和" + e[1];

      default:
        return e.slice(0, e.length - 1).join(", ") + ", 和 " + e[e.length - 1];
    }
  }(smallSeg))
    .replace("every 1st", "every")
    .replace(meaning + " every", "every")
    .replace(", " + meaning, ", ")
    .replace(", and " + meaning, ", and ");
}

const oneOrTwoDigitsReg = /^0*\d\d?$/;

export const describeCrontab = function (e: PreNormalized) {

  const parts = e.parts;

  const minuteSeg = parts[0]
  const hourSeg = parts[1]
  const daySeg = parts[2]
  const monthSeg = parts[3]
  const weekSeg = parts[4]

  let dayDesc: string;
  if ("*" === daySeg) {
    dayDesc = "";
  } else {
    dayDesc = new DatePartDescriber(daySeg).describe()
  }


  const monthDesc = monthSeg === '*' ? '' : new MonthPartDescriber(monthSeg).describe()
  const weekDesc = "*" === weekSeg ? "" : new WeekPartDescriber(weekSeg).describe()

  const daysAndWeeks = weekSeg.indexOf('*') === 0 || weekSeg.indexOf('*') === 0

  const minutesDesc = new MinutePartDescriber(minuteSeg).describe()
  const hourDesc = "*" === hourSeg ? "" : new HourPartDescriber(hourSeg).describe()

  function fullDateWhenDaysOrWeeks(dayDesc: string, weekDesc: string, month: string): string {
    if (dayDesc && weekDesc) {

      const d = `${dayDesc}`.trim()
      const w = `${month}的${weekDesc}`.trim()

      return `${d} 或者 ${w}`

    } else {

      return dayDesc || weekDesc
    }
  }

  function fullDateWhenDaysAndWeeks(dayDesc: string, weedDesc: string, monthDesc: string): string {
    if (dayDesc && weedDesc) {
      return `${dayDesc}(并且是${weekDesc})`
    }

    return dayDesc || weedDesc
  }

  const dayFull = daysAndWeeks ?
    fullDateWhenDaysAndWeeks(dayDesc, weekDesc, monthDesc) :
    fullDateWhenDaysOrWeeks(dayDesc, weekDesc, monthDesc)

  let pre = '每'

  if (minutesDesc && !minutesDesc.startsWith('每')) {
    pre = '每小时 '
  }

  if (hourDesc && !hourDesc.startsWith('每')) {
    pre = '每天 '
  }

  if (dayDesc && !dayDesc.startsWith('每')) {
    pre = '每月 '
  }

  if (weekDesc && !weekDesc.startsWith('每')) {
    pre = '每'
  }

  if (monthDesc && !monthDesc.startsWith('每')) {
    pre = '每年 '
  }

  const descFull = `${monthDesc} ${dayFull} ${hourDesc} ${minutesDesc}`.trim()
    .replace(/\s{2,}/g, ' ')

  return {
    start: "At",
    minutes: minutesDesc || null,
    hours: hourDesc || null,
    isTime: true,
    dates: dayDesc || null,
    weekdays: weekDesc || null,
    months: monthDesc || null,
    end: ".",
    descFull,
    full: `${pre}${descFull}`
  };
};
